package com.typ.member.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.typ.member.common.enums.OpTypeEnum;
import com.typ.member.common.enums.StatusEnum;
import com.typ.member.common.excepiton.BadArgumentException;
import com.typ.member.common.excepiton.BusinessException;
import com.typ.member.common.model.PageRequest;
import com.typ.member.common.utils.CodeUtil;
import com.typ.member.dao.mapper.MemberCardDtoMapper;
import com.typ.member.dao.mapper.MemberTradeDtoMapper;
import com.typ.member.dao.model.MemberCardDto;
import com.typ.member.dao.model.MemberCardQueryDto;
import com.typ.member.dao.model.MemberTradeDto;
import com.typ.member.dao.model.ProcessDto;
import com.typ.member.service.MemberCardService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * 会员卡信息接口
 *
 * @author heran
 * @version 1.0, 2019-05-10 13:32
 */
@Service
@Slf4j
public class MemberCardServiceImpl implements MemberCardService {

    @Resource
    private MemberCardDtoMapper memberCardDtoMapper;
    @Resource
    private MemberTradeDtoMapper memberTradeDtoMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(MemberCardDto memberCardDto) {
        //参数校验
        paramCheck(memberCardDto);

        //验证会员卡是否重复
        checkMemeberCardDuplicate(memberCardDto);
        //补全必要的信息
        fillMemberCardDto(memberCardDto);

        //保存会员卡信息
        memberCardDtoMapper.insert(memberCardDto);
        //保存交易记录
        MemberTradeDto memberTradeDto = buildMemberTradeDto(memberCardDto, "新会员注册");
        memberTradeDtoMapper.insert(memberTradeDto);
        //保存充值记录
        if (memberCardDto.getBalance() != null) {
            memberTradeDto.setOpType(OpTypeEnum.BALANCE_RECHARGE.getCode());
            memberTradeDto.setOpVal(String.valueOf(memberCardDto.getBalance()));
            memberTradeDto.setRemark("会员首次充值");
            memberTradeDtoMapper.insert(memberTradeDto);
        }

    }

    @Override
    public void update(MemberCardDto memberCardDto) {
        if (memberCardDto == null || memberCardDto.getId() == null) {
            throw new BadArgumentException("会员卡ID不能为空");
        }
        memberCardDtoMapper.updateByPrimaryKeySelective(memberCardDto);
    }

    @Override
    public void delete(Long id) {
        memberCardDtoMapper.deleteByPrimaryKey(id);
    }

    @SuppressWarnings("Duplicates")
    @Override
    public PageInfo<MemberCardDto> search(MemberCardQueryDto memberCardQueryDto, PageRequest pageRequest) {
        Page<MemberCardDto> page = PageHelper.startPage(pageRequest.getPage(), pageRequest.getPageSize());
        List<MemberCardDto> memberCardDtos = memberCardDtoMapper.selectByQuery(memberCardQueryDto);
        PageInfo<MemberCardDto> pageInfo = new PageInfo<>(page);
        pageInfo.setList(memberCardDtos);
        return pageInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doConsume(ProcessDto processDto) {
        MemberCardDto memberCardDto = checkMemberCardExist(processDto.getCardId());

        BigDecimal balance = memberCardDto.getBalance();
        if (balance.subtract(processDto.getVal()).compareTo(BigDecimal.ZERO) < 0) {
            throw new BusinessException("余额不足，请充值");
        }

        memberCardDto.setBalance(balance.subtract(processDto.getVal()));
        memberCardDto.setModified(new Date());
        memberCardDto.setEditor(processDto.getPin());
        //更新
        update(memberCardDto);
        //保存交易记录
        saveTrade(memberCardDto, processDto, OpTypeEnum.BALANCE_CONSUME);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doRecharge(ProcessDto processDto) {
        MemberCardDto memberCardDto = checkMemberCardExist(processDto.getCardId());

        BigDecimal balance = memberCardDto.getBalance();
        memberCardDto.setBalance(balance.add(processDto.getVal()));
        memberCardDto.setPoints(memberCardDto.getPoints().add(processDto.getVal()));
        memberCardDto.setModified(new Date());
        memberCardDto.setEditor(processDto.getPin());

        //更新
        update(memberCardDto);
        //保存交易记录
        saveTrade(memberCardDto, processDto, OpTypeEnum.BALANCE_RECHARGE);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doPointsConsume(ProcessDto processDto) {
        MemberCardDto memberCardDto = checkMemberCardExist(processDto.getCardId());

        BigDecimal points = memberCardDto.getPoints();
        if (points.subtract(processDto.getVal()).compareTo(BigDecimal.ZERO) < 0) {
            throw new BusinessException("积分不足，赶快充值吧");
        }
        memberCardDto.setPoints(points.subtract(processDto.getVal()));
        memberCardDto.setModified(new Date());
        memberCardDto.setEditor(processDto.getPin());

        //更新
        update(memberCardDto);
        //保存交易记录
        saveTrade(memberCardDto, processDto, OpTypeEnum.POINTS_CONSUME);
    }

    /**
     * 保存交易记录
     *
     * @param memberCardDto
     * @param processDto
     * @param opTypeEnum
     */
    private void saveTrade(MemberCardDto memberCardDto, ProcessDto processDto, OpTypeEnum opTypeEnum) {
        //保存交易记录
        MemberTradeDto memberTradeDto = buildMemberTradeDto(memberCardDto, processDto.getRemark());
        memberTradeDto.setOpType(opTypeEnum.getCode());
        memberTradeDto.setCreator(processDto.getPin());
        memberTradeDto.setEditor(processDto.getPin());
        if (null != processDto.getVal()) {
            memberTradeDto.setOpVal(processDto.getVal().toString());
        }
        memberTradeDtoMapper.insert(memberTradeDto);
    }

    /**
     * 验证会员卡是否存在
     *
     * @param cardId
     * @return
     */
    private MemberCardDto checkMemberCardExist(Long cardId) {
        MemberCardDto memberCardDto = memberCardDtoMapper.selectByPrimaryKey(cardId);
        if (null == memberCardDto) {
            log.error("member card not exist,cardId = {}", cardId);
            throw new BusinessException("会员卡不存在");
        }
        return memberCardDto;
    }

    /**
     * 补全必要的信息
     *
     * @param memberCardDto
     */
    private void fillMemberCardDto(MemberCardDto memberCardDto) {
        memberCardDto.setCode(CodeUtil.generateCode());
        memberCardDto.setStatus(StatusEnum.NORMAL.getCode());
        memberCardDto.setCreated(new Date());
        memberCardDto.setModified(new Date());
        processPoints(memberCardDto);
    }

    /**
     * 处理积分
     *
     * @param memberCardDto
     */
    private void processPoints(MemberCardDto memberCardDto) {
        if (memberCardDto.getBalance() != null) {
            if (memberCardDto.getPoints() != null) {
                memberCardDto.setPoints(memberCardDto.getPoints().add(memberCardDto.getBalance()));
            } else {
                memberCardDto.setPoints(memberCardDto.getBalance());
            }
        }
    }

    /**
     * 构建MemberTradeDto
     *
     * @param memberCardDto
     * @return
     */
    private MemberTradeDto buildMemberTradeDto(MemberCardDto memberCardDto, String remark) {
        MemberTradeDto memberTradeDto = new MemberTradeDto();
        memberTradeDto.setCardId(memberCardDto.getId());
        memberTradeDto.setName(memberCardDto.getName());
        memberTradeDto.setPhone(memberCardDto.getPhone());
        memberTradeDto.setOpType(OpTypeEnum.MEMBER_REGISTER.getCode());
        memberTradeDto.setOpVal(null);
        memberTradeDto.setCreated(new Date());
        memberTradeDto.setCreator(memberCardDto.getCreator());
        memberTradeDto.setModified(new Date());
        memberTradeDto.setEditor(memberCardDto.getEditor());
        memberTradeDto.setRemark(remark);
        memberTradeDto.setStatus(StatusEnum.NORMAL.getCode());
        return memberTradeDto;
    }

    /**
     * 参数验证
     *
     * @param memberCardDto
     */
    private void paramCheck(MemberCardDto memberCardDto) {
        if (memberCardDto == null) {
            throw new BadArgumentException("会员卡信息不能为空");
        }
        if (StringUtils.isEmpty(memberCardDto.getName())) {
            throw new BadArgumentException("会员卡信息-名称不能为空");
        }
        if (StringUtils.isEmpty(memberCardDto.getPhone())) {
            throw new BadArgumentException("会员卡信息-电话号码不能为空");
        }
    }

    /**
     * 验证会员卡是否重复
     *
     * @param memberCardDto
     */
    private void checkMemeberCardDuplicate(MemberCardDto memberCardDto) {
        MemberCardQueryDto memberCardQueryDto = new MemberCardQueryDto();
        memberCardQueryDto.setName(memberCardDto.getName());
        memberCardQueryDto.setPhone(memberCardDto.getPhone());
        List<MemberCardDto> memberCardDtos = memberCardDtoMapper.selectByQuery(memberCardQueryDto);
        if (!CollectionUtils.isEmpty(memberCardDtos)) {
            log.error("member card already exist,memberCardDto={}", memberCardDto);
            throw new BusinessException("该会员卡已经存在，会员ID为" + memberCardDtos.get(0).getId());
        }
    }
}
